#!/bin/sh

. $SNAP/utilities/https-utilities

COMMAND="nextcloud.enable-https"

print_usage()
{
	echo "Usage:"
	echo "    $COMMAND -h"
	echo "    Display this help message."
	echo ""
	echo "    $COMMAND <subcommand> [OPTIONS]"
	echo "    Run the provided subcommand."
	echo ""
	echo "Available subcommands:"
	echo "    lets-encrypt [OPTIONS]"
	echo "    Obtain a certificate from Let's Encrypt and automatically keep it"
	echo "    up-to-date."
	echo ""
	echo "    self-signed"
	echo "    Generate and use a self-signed certificate. This is easier to"
	echo "    setup than Let's Encrypt certificates, but will cause warnings in"
	echo "    browsers."
	echo ""
	echo "    custom [OPTIONS]"
	echo "    Use certificates generated by other means."
}

handle_lets_encrypt()
{
	extra_params=""
	dry_run=false

	while getopts ":dth" opt; do
		case $opt in
			d)
				extra_params="$extra_params --dry-run"
				dry_run=true
				;;
			t) extra_params="$extra_params --test-cert";;
			h)
				echo "Usage:"
				echo "    $COMMAND lets-encrypt [-h -t -d]"
				echo ""
				echo "    Obtain a certificate from Let's Encrypt and"
				echo "    automatically keep it up to date."
				echo ""
				echo "    -h: Display this help message"
				echo "    -t: Obtain a test certificate. This is a valid Let's"
				echo "        Encrypt certificate, but is not signed by a"
				echo "        recognized CA, so browsers will show a warning."
				echo "    -d: Dry run: don't actually obtain/install"
				echo "        certificates from Let's Encrypt, but make sure"
				echo "        it's possible."
				exit 0
				;;
			\?)
				echo "Invalid option: -$OPTARG" >&2
				exit 1
				;;
		esac
	done

	echo "In order for Let's Encrypt to verify that you actually own the"
	echo "domain(s) for which you're requesting a certificate, there are a"
	echo "number of requirements of which you need to be aware:"
	echo ""

	echo "1. In order to register with the Let's Encrypt ACME server, you must"
	echo "   agree to the currently-in-effect Subscriber Agreement located"
	echo "   here:"
	echo ""
	echo "       https://letsencrypt.org/repository/"
	echo ""
	echo "   By continuing to use this tool you agree to these terms. Please"
	echo "   cancel now if otherwise."
	echo ""

	echo "2. You must have the domain name(s) for which you want certificates"
	echo "   pointing at the external IP address of this machine."
	echo ""

	echo "3. Both ports 80 and 443 on the external IP address of this machine"
	echo "   must point to this machine (e.g. port forwarding might need to be"
	echo "   setup on your router)."
	echo ""

	while true; do
		read -p "Have you met these requirements? (y/n) " answer
		case $answer in
			[Yy]* ) break;;
			[Nn]* ) exit;;
			* ) echo "Please answer yes or no.";;
		esac
	done

	read -p "Please enter an email address (for urgent notices or key recovery): " email

	domains=""
	read -p "Please enter your domain name(s) (space-separated): " answer
	for domain in $answer; do
		domains="$domains -d $domain"
	done

	echo -n "Attempting to obtain certificates... "
	output=$(run_certbot certonly $extra_params \
	         --authenticator nextcloud:webroot \
	         --nextcloud:webroot-path $CERTBOT_DIRECTORY \
	         --rsa-key-size 4096 \
	         --email $email \
	         --non-interactive \
	         --agree-tos \
	         --force-renewal \
	         $domains 2>&1)
	if [ $? -ne 0 ]; then
		echo "error running certbot:" >&2
		echo "" >&2
		echo "$output" >&2
		exit 1
	fi

	echo "done"
	if [ "$dry_run" = true ]; then
		echo "Looks like you're ready for HTTPS!"
	else
		activate_certbot_certificate
	fi
}

handle_self_signed()
{
	while getopts ":h" opt; do
		case $opt in
			h)
				echo "Usage:"
				echo "    $COMMAND self-signed [-h]"
				echo ""
				echo "    Generate and use a self-signed certificate. This is"
				echo "    easier to setup than Let's Encrypt certificates, but"
				echo "    will cause warnings in browsers."
				echo ""
				echo "    -h: Display this help message"
				exit 0
				;;
			\?)
				echo "Invalid option: -$OPTARG" >&2
				exit 1
				;;
		esac
	done

	echo -n "Generating key and self-signed certificate... "
	output=$(generate_self_signed_certificate 2>&1)
	if [ $? -ne 0 ]; then
		echo "error:" >&2
		echo "$output" >&2
		exit 1
	fi

	echo "done"
	activate_self_signed_certificate
}

handle_custom()
{
	enable_hsts=false

	while getopts ":hs" opt; do
		case $opt in
			h)
				echo "Usage:"
				echo "    $COMMAND custom [-h -s] <cert> <key> <chain>"
				echo ""
				echo "    Use certificates generated by other means. Note that"
				echo "    the files provided to this command must be readable"
				echo "    by the snap, which means they must contained in one"
				echo "    of four directory trees:"
				echo "      - $SNAP_CURRENT"
				echo "      - $SNAP_COMMON"
				echo "      - $SNAP_USER_DATA"
				echo "      - $SNAP_USER_COMMON"
				echo ""
				echo "    Also note that this command will create copies of the"
				echo "    files provided; if this command completes"
				echo "    successfully, they can be safely removed."
				echo ""
				echo "    -h: Display this help message."
				echo "    -s: Enable HTTP Strict Transport Security (HSTS)"
				echo "        (default is off-- leave off if self-signed)."
				exit 0
				;;
			s)
				enable_hsts=true
				;;
			\?)
				echo "Invalid option: -$OPTARG" >&2
				exit 1
				;;
		esac
	done
	shift $((OPTIND-1))

	if [ $# -ne 3 ]; then
		echo -n "This subcommand requires three positional parameters: " >&2
		echo "<cert> <key> <chain>" >&2
		exit 1
	fi

	certificate=$1
	private_key=$2
	chain=$3

	echo -n "Installing custom certificate... "
	output=$(install_custom_certificate \
	         $certificate $private_key $chain $enable_hsts 2>&1)
	if [ $? -ne 0 ]; then
		echo "error:" >&2
		echo "$output" >&2
		exit 1
	fi

	echo "done"
	activate_custom_certificate
}

if [ $(id -u) -ne 0 ]; then
	echo "This utility needs to run as root"
	exit 1
fi

# Parse options for the base command
while getopts ":h" opt; do
	case $opt in
		h)
			print_usage
			exit 0
			;;
		\?)
			echo "Invalid option: -$OPTARG" >&2
			exit 1
			;;
	esac
done
shift $((OPTIND-1))

if [ $# = 0 ]; then
	echo "Missing subcommand. Run '$COMMAND -h' for help." >&2
	exit 1
fi

subcommand=$1
shift # Remove subcommand from args
case $subcommand in
	lets-encrypt)
		handle_lets_encrypt "$@"
		;;
	self-signed)
		handle_self_signed "$@"
		;;
	custom)
		handle_custom "$@"
		;;
	*)
		echo "No such subcommand: $subcommand. Run '$COMMAND -h' for help." >&2
		exit 1
		;;
esac
